package com.example.score.service;

import com.example.score.dto.FiveRate;
import com.example.score.entity.StudentSubmit;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.List;
import java.util.stream.Collectors;

@Service
public class CommonUtils {
    public static double calculateMaxScore(List<StudentSubmit> submits) {
        return Math.round(submits.stream()
                .mapToDouble(StudentSubmit::getScore)
                .max()
                .orElse(0) * 100.0) / 100.0;
    }

    // 计算总分平均分
    public static double calculateAverageScore(List<StudentSubmit> submits) {
        if (submits.isEmpty()) {
            return 0.0;
        }
        return submits.stream()
                .mapToDouble(StudentSubmit::getScore)
                .filter(score -> score >= 0)
                .average()
                .orElse(0.0);
    }


    // 计算最低分
    public static double calculateMinScore(List<StudentSubmit> submits) {
        return Math.round(submits.stream()
                .mapToDouble(StudentSubmit::getScore)
                .min()
                .orElse(0) * 100.0) / 100.0;
    }

    public static double calculateStandardDeviationForSubmits(List<StudentSubmit> submits) {
        if (submits.isEmpty()) {
            return 0.00;
        }

        // 1. 求平均值
        double mean = submits.stream()
                .mapToDouble(StudentSubmit::getScore)
                .average()
                .orElse(0.0);

        // 2&3. 计算每次得分与平均值的差的平方
        double squareSum = submits.stream()
                .mapToDouble(s -> Math.pow(s.getScore() - mean, 2))
                .sum();  // 4. 累加平方差

        // 5. 计算方差 = 平方差/次数
        double variance = squareSum / submits.size();

        // 6. 开根号得到标准差
        return Math.round(Math.sqrt(variance) * 100.0) / 100.0;  // 保留两位小数
    }

    public static double calculateExcellentRate(List<StudentSubmit> submits, int fullScore) {
        if (submits.isEmpty()) {
            return 0.00;
        }

        List<StudentSubmit> validSubmits = submits.stream()
                .filter(s -> s.getSubmitStatus() == 1)
                .collect(Collectors.toList());

        if (validSubmits.isEmpty()) {
            return 0.00;
        }

        BigDecimal threshold = BigDecimal.valueOf(fullScore)
                .multiply(BigDecimal.valueOf(0.85));


        long excellentCount = validSubmits.stream()
                .filter(s -> BigDecimal.valueOf(s.getScore())
                        .compareTo(threshold) >= 0)
                .count();

        double rate = BigDecimal.valueOf(excellentCount)
                .multiply(BigDecimal.valueOf(100.0))
                .divide(BigDecimal.valueOf(validSubmits.size()), 2, RoundingMode.HALF_UP)
                .doubleValue();


        return rate;
    }

    public static double calculatePassRate(List<StudentSubmit> submits, int fullScore) {
        if (submits.isEmpty()) {
            return 0.00;
        }
        double passThreshold = fullScore * 0.60; // 60分及格
        long passCount = submits.stream()
                .filter(s -> s.getScore() >= passThreshold)
                .count();
        return Math.round((passCount * 100.0 / submits.size()) * 100.0) / 100.0;
    }

    public static double calculateMedianScore(List<StudentSubmit> submits) {
        if (submits.isEmpty()) {
            return 0.00;
        }
        List<Double> scores = submits.stream()
                .map(StudentSubmit::getScore)
                .sorted()
                .collect(Collectors.toList());
        int size = scores.size();
        double median;
        if (size % 2 == 0) {
            median = (scores.get(size / 2 - 1) + scores.get(size / 2)) / 2.0;
        } else {
            median = scores.get(size / 2);
        }
        return Math.round(median * 100.0) / 100.0;
    }

    // 计算客观题平均分
    public static double calculateObjectiveAverage(List<StudentSubmit> submits) {
        if (submits.isEmpty()) {
            return 0.0;
        }
        return submits.stream()
                .mapToDouble(StudentSubmit::getObjectiveScore)
                .filter(score -> score >= 0)  // 过滤无效分数
                .average()
                .orElse(0.0);
    }

    // 计算主观题平均分
    public static double calculateSubjectiveAverage(List<StudentSubmit> submits) {
        if (submits.isEmpty()) {
            return 0.0;
        }
        return submits.stream()
                .mapToDouble(StudentSubmit::getSubjectiveScore)
                .filter(score -> score >= 0)  // 过滤无效分数
                .average()
                .orElse(0.0);
    }

    public static double calculatePercentile(List<Double> scores, int percentile) {
        if (scores.isEmpty()) {
            return 0;
        }

        int index = (int) Math.ceil(scores.size() * percentile / 100.0) - 1;
        return scores.get(Math.max(0, Math.min(scores.size() - 1, index)));
    }

    // 格式化数字，保留2位小数
    public static String formatNumber(double number) {
        return String.format("%.2f", number);
    }

    // 计算客观题标准差
    public static double calculateObjectiveStdDev(List<StudentSubmit> submits) {
        double mean = CommonUtils.calculateObjectiveAverage(submits);
        return Math.sqrt(submits.stream()
                .mapToDouble(s -> Math.pow(s.getObjectiveScore() - mean, 2))
                .average()
                .orElse(0.0));
    }

    // 计算主观题标准差
    public static double calculateSubjectiveStdDev(List<StudentSubmit> submits) {
        double mean = CommonUtils.calculateSubjectiveAverage(submits);
        return Math.sqrt(submits.stream()
                .mapToDouble(s -> Math.pow(s.getSubjectiveScore() - mean, 2))
                .average()
                .orElse(0.0));
    }

    // 计算满分人数
    public static int countFullScore(List<StudentSubmit> submits, List<FiveRate> fiveRates) {
        FiveRate fiveRate = fiveRates.stream().filter(fr-> fr.getType() == 0).findFirst().get();
        if(ObjectUtils.isEmpty(fiveRate)){
            return 0;
        }
        return (int) submits.stream()
                .filter(s -> s.getScore() >= fiveRate.getStartScore())
                .count();
    }

    // 计算优秀人数 (90分以上)
    public static int countExcellent(List<StudentSubmit> submits, List<FiveRate> fiveRates) {
        FiveRate fiveRate = fiveRates.stream().filter(fr-> fr.getType() == 1).findFirst().get();
        if(ObjectUtils.isEmpty(fiveRate)){
           return 0;
        }
        return (int) submits.stream()
                .filter(s -> s.getScore() < fiveRate.getEndScore() && s.getScore() >= fiveRate.getStartScore())
                .count();
    }

    // 计算良好人数 (80-90分)
    public static int countGood(List<StudentSubmit> submits, List<FiveRate> fiveRates) {
        FiveRate fiveRate = fiveRates.stream().filter(fr-> fr.getType() == 2).findFirst().get();
        if(ObjectUtils.isEmpty(fiveRate)){
            return 0;
        }
        return (int) submits.stream()
                .filter(s -> s.getScore() < fiveRate.getEndScore() && s.getScore() >= fiveRate.getStartScore())
                .count();
    }

    // 计算及格人数 (60-80分)
    public static int countPass(List<StudentSubmit> submits, List<FiveRate> fiveRates) {
        FiveRate fiveRate = fiveRates.stream().filter(fr-> fr.getType() == 3).findFirst().get();
        if(ObjectUtils.isEmpty(fiveRate)){
            return 0;
        }
        return (int) submits.stream()
                .filter(s -> s.getScore() < fiveRate.getEndScore() && s.getScore() >= fiveRate.getStartScore())
                .count();
    }

    // 计算低分人数 (60分以下)
    public static int countLow(List<StudentSubmit> submits, List<FiveRate> fiveRates) {
        FiveRate fiveRate = fiveRates.stream().filter(fr-> fr.getType() == 4).findFirst().get();
        if(ObjectUtils.isEmpty(fiveRate)){
            return 0;
        }
        return (int) submits.stream()
                .filter(s -> s.getScore() < fiveRate.getEndScore() && s.getScore() >= fiveRate.getStartScore())
                .count();
    }

    public static  String formatRate(int count, int total) {
        if (total == 0) return "0.00";
        return String.format("%.2f%%", count * 100.0 / total);
    }

}
